package sketch.main;

import java.util.LinkedList;
import java.util.List;

import plume.Option;
import plume.Options;
import sketch.ounit.fuzz.AssembledSequence;
import sketch.ounit.fuzz.ImprovedSketchGuidedRandomTestGeneration;
import sketch.util.IntermediateFiles;
import sketch.util.SketchUtil;

/**
 * The main entry for sketch-guided test generation
 * */
public class SketchGuidedRandomGenMain {
	
	@Option(value="Print usage of SketchTest options")
	public static boolean help = false;
	
	@Option(value="Print all debugging information")
	public static boolean verbose = true;
	
	@Option(value = "Remove all intermediate output")
	public static boolean release = true;
	
	@Option(value = "Delete all intermediate files or not")
	public static boolean difiles = false;
	
	/**
	 * The following four options must be setted
	 * */
	@Option(value="The input test sketch, full path")
	public static String test_sketch = null;
	
	@Option(value="The JUnit class name in the given test sketch")
	public static String junit_class = null;
	
	@Option(value="The randomize time to create an object pool, in seconds")
	public static int random_time = -1;
	
	@Option(value="The fuzz time to create tests guided by sketching, in seconds")
	public static int fuzz_time = -1;
	
	/**
	 * Some optional options
	 * */
	@Option(value="The output dir for generated tests")
	public static String output_dir = "./output/";
	
	@Option(value="The dir which must be in classpath for storing all intermediate result")
	public static String dir_in_classpath = null;
	
	@Option(value="The JUnit method append")
	public static String junit_method_append = null;
	
	@Option(value="The prefix of JUnit class")
	public static String junit_class_prefix = null;
	
	@Option(value = "The max number of tests to create")
	public static int maxTestNum = -1;
	
	@Option(value="The number of tests per file")
	public static int testPerFile = -1;
	
	@Option(value="The name of output package")
	public static String outputPackageName = null;
	
	@Option(value="The choice of outputting randoop tests or not")
	public static boolean outputRandoopTest = false;
	
	@Option(value="The probability of using a user-provided object as argument")
	public static int user_objects_prob = -1;
	
	/**
	 * The main entry
	 * */
	public static void main(String[] args) {
//		args = new String[]{"--test_sketch=./tmp/RandomTestSketchExample.java", "--junit_class=sketch.test.RandomTestSketchExample"
//				, "--random_time=5", "--fuzz_time=10"};
		Options options = new Options("Options for sketch-guided random test generation.", SketchGuidedRandomGenMain.class);
		String[] file_args = options.parse_or_usage(args);
		//errors in parsing the arguments
		if(file_args.length != 0) {
			SketchUtil.flushToStd(file_args);
			System.exit(1);
		}
		//check the argument validity
		String[] errorMsgs = checkArgumentValidity();
		if(errorMsgs.length != 0) {
			SketchUtil.flushToStd(errorMsgs);
			System.exit(1);
		}
		
		//check the validity of a given test_sketch
		TestSketchValidator validator = new TestSketchValidator(test_sketch);
		String[] error_messages = validator.validate();
		if(error_messages.length != 0) {
			SketchUtil.flushToStd(error_messages);
			System.exit(1);
		}
		
		//start to generate
		ImprovedSketchGuidedRandomTestGeneration generator
		  = new ImprovedSketchGuidedRandomTestGeneration(test_sketch, junit_class, random_time, fuzz_time);
		//configure the options
		configureTestGenOptions(generator);
		//generating tests
		generator.generate_tests();
		
		//delete intermediate files
		if(SketchGuidedRandomGenMain.difiles) {
		    IntermediateFiles.deleteIntermediateFiles();
		}
	}
	
	private static String[] checkArgumentValidity() {
		List<String> errorMsg = new LinkedList<String>();
		if(test_sketch == null) {
			errorMsg.add("use --test_sketch to set up the name of a sketch.");
		}
		if(junit_class == null) {
			errorMsg.add("use --junit_class to set up the name of a junit class.");
		}
		if(random_time == -1) {
			errorMsg.add("use --random_time to set up the random generating time, must > 0");
		}
		if(fuzz_time == -1) {
			errorMsg.add("use --fuzz_time to set up the fuzzing time, must > 0");
		}
		if(!SketchUtil.isDirInClasspath(SketchTestOptions.output_dir)) {
			errorMsg.add("The dir: " + output_dir + " is not in your classpath, please set it by --output_dir option");
		} else {
			SketchTestOptions.output_dir = SketchGuidedRandomGenMain.output_dir;
		}
		return (String[])errorMsg.toArray(new String[0]);
	}
	
	private static void configureTestGenOptions(ImprovedSketchGuidedRandomTestGeneration generator) {
//		if(output_dir != null) {
//			generator.setOutput_dir(output_dir);
//		}
		if(dir_in_classpath != null) {
			generator.setTmp(dir_in_classpath);
		}
		if(junit_method_append != null) {
			generator.setJunit_method_append(junit_method_append);
		}
		if(junit_class_prefix != null) {
			generator.setJunit_class_prefix(junit_class_prefix);
		}
		if(maxTestNum != -1) {
			generator.setMaxTestNum(maxTestNum);
		}
		if(testPerFile != -1) {
			generator.setTestPerFile(testPerFile);
		}
		if(outputPackageName != null) {
			generator.setOutputPackageName(outputPackageName);
		}
		if(outputRandoopTest) {
			generator.setOutputRandoopTest(outputRandoopTest);
		}
		GeneratingTests.release = SketchGuidedRandomGenMain.release;
//		if(user_objects_prob > -1) {
//			AssembledSequence.use_arg_probability = (float)((float)user_objects_prob / 10);
//		}
	}
}